home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 1
/
Cream of the Crop 1.iso
/
PROGRAM
/
BCCAPP.ARJ
/
POPUP.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-09-15
|
8KB
|
380 lines
/*
*
* Class Implementation for Popup menu system
*
* (C) 1990 Vision Software
*
* $Id: popup.c 1.2001 91/04/25 15:07:51 pcalvin release $
*
* Comments:
*
* Superclass POPUP menus. This class provides popup menuing capabilities.
* In addition, we have the base class for all scroll/menus etc..
*
* Bugs:
*
* None documented
*
*/
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include <ctype.h>
#include <dos.h>
#include <stdhdr.h>
#include <adl.h>
#include <menu.h>
#include "lowlevel.h"
/*
* Public constructors, used by the general public for
* Straight forward popup menus..
*/
POPUP::POPUP(ROW row,COL col,CENT centMenu,PENT pentMenu,SZ sz) : help(szNil)
{
cchMenuMax = cchNil;
rowTop = row;
colLeft = col;
centMax = centMenu;
pentBase = pentMenu;
szTitle = sz;
}
/*
* Protected constructors. These are used by the Pulldown system
* and others to build popups as needed.
*/
POPUP::POPUP(SZ sz) : help(szNil)
{
cchMenuMax = cchNil;
pentBase = pentNil;
szTitle = sz;
}
/*
* Get routine called by derived classes to adjust menu dynamically
*/
CENT POPUP::CentGet(ROW row,COL col,CENT cent,PENT pentMenu)
{
colLeft = col;
rowTop = row;
centMax = cent;
pentBase = pentMenu;
return (CentGet());
}
/*
* Answers with the key that exited the previous POPUP
*/
CD POPUP::CdExitKey(VOID)
{
return (cdLastKey);
}
/*
* Get routine available to the general public, popup must be set
* at declaration time..
*/
CENT POPUP::CentGet()
{
CURSOR crs(fFalse);
/*
* Place popup on the screen if needed.
* Set flag to remove at end..
*/
Show();
if (pentBase != pentNil)
help.Replace(pentBase[centAnswer].szQuickHelp);
/*
* Loop until menu is terminated.
*/
while (FHandleCd(centAnswer,cdLastKey = CdInput(),pentBase,wnd))
Display(centAnswer,pentBase,wnd,fTrue);
/*
* An indication of the selected entry. This flash is NOT done if
* the selected entry is the root of a sub-menu. Otherwise, we
* would have flashes all over the screen as sub-menus are unwound.
*/
if (centAnswer != centError && pentBase[centAnswer].pentNext == pentNil)
Flash(centAnswer,pentBase,wnd);
/*
* If this Get is not Re-entrant, remove it from the screen..
*/
Hide();
/*
* If a selection was made, attempt to call that function
*/
if ((centAnswer != centError) && (pentBase != pentNil))
{
if (pentBase[centAnswer].pfnFunction != Nil)
pentBase[centAnswer].pfnFunction();
}
return (centAnswer);
}
/*
* Puts popup onto the screen
*/
VOID POPUP::Show(VOID)
{
/*
* Compute size of window and open it..
*/
rowTop = RowTopFromCentPent(centMax,pentBase);
colLeft = ColLeftFromCentPent(centMax,pentBase);
rowBottom = CrowFromCentPent(centMax,pentBase) + rowTop+1;
colRight = CcolFromCentPent(centMax,pentBase) + colLeft+1;
/*
* Now, simply create the window..
*/
wnd = WINDOW(rowTop+2,colLeft,rowBottom,colRight,coBlack,coCyan,szTitle);
wnd.Open();
/*
* Fill in related information
*/
Redraw();
/*
* First member is selected
*/
Display(centNil,pentBase,wnd,fTrue);
centAnswer = centNil;
}
/*
* Removes the popup from the screen..
*/
VOID POPUP::Hide(VOID)
{
wnd.Close();
}
/*
* Redraws the selections
*/
VOID POPUP::Redraw(VOID)
{
for (CENT cent = centNil; cent < centMax; cent++)
Display(cent,pentBase,wnd,fFalse);
}
/*
* Called by Redraw() to display individual entries..
*/
VOID POPUP::Display(CENT cent,PENT pent,WINDOW &rwnd,BOOL fSelected)
{
PointerAssert(pent);
PointerAssert(pent[cent].sz);
CO coBack = fSelected ? coGreen : coCyan;
SZ sz = SzFromCentPent(cent,pent);
CCH cch = pent[cent].cchHotKey+1;
rwnd.SayHot(cent,0,sz,cch,coBlack,coBack);
}
/*
* This is the base level handling for Keyboard input. This virtual
* function answers if the input should continue.
* Additionally, the first formal parameter (CENT &rcent) answers with
* the new selected entry
*/
BOOL POPUP::FHandleCd(CENT &rcent,CD cd,PENT pent,WINDOW &rwnd)
{
BOOL fContinue = fTrue;
/*
* Defaults to no exit, must prove otherwise.
*/
switch (cd)
{
case cdEscape:
/*
* The escape key, Unless trapped by a derived class
* Quits the popup..
*/
rcent = centError;
fContinue = fFalse;
break;
case cdReturn:
/*
* If a derived class is not using the standard MENU entries,
* It had BETTER trap the return key.
* If they are not, the program will ASSERT right here.
*/
Assert(pent != pentNil);
Assert(pent->sz != szNil);
/*
* If there is a sub-menu, display it..
*/
if (pent[rcent].pentNext != pentNil)
{
fContinue = FSubMenuFromCentPent(rcent,pent);
}
else
{
cdLastKey = pent[rcent].sz[pent[rcent].cchHotKey];
fContinue = fFalse;
}
break;
case cdCursorUp:
if (rcent > 0)
{
Display(rcent,pent,rwnd,fFalse);
rcent -= 1;
help.Replace(pent[rcent].szQuickHelp);
}
break;
case cdCursorDown:
if (rcent+1 < centMax)
{
Display(rcent,pent,rwnd,fFalse);
rcent += 1;
help.Replace(pent[rcent].szQuickHelp);
}
break;
default:
if (pentBase != pentNil && isascii(cd))
{
CHAR ch = toupper(cd);
for (CENT centKey = centNil; fContinue && centKey < centMax; centKey++)
{
/*
* Search array for matching key.
*/
if (toupper(pent[centKey].sz[pent[centKey].cchHotKey]) == ch)
{
Display(rcent,pent,rwnd,fFalse);
cdLastKey = (CD)pent[centKey].sz[pent[centKey].cchHotKey];
rcent = centKey;
/*
* If this menu has a sub-menu, move the highlight over the
* selected member and activate the sub-menu
*/
if (pent[centKey].pentNext != pentNil)
{
Display(rcent,pent,rwnd,fTrue);
fContinue = FSubMenuFromCentPent(centKey,pent);
}
else
{
fContinue = fFalse;
}
}
}
}
}
return (fContinue);
}
/*
* Builds a temporary string for output. This string is padded with
* a space on the left and right
*/
VOLATILE SZ POPUP::SzFromCentPent(CENT cent,PENT pent)
{
PointerAssert(pent);
PointerAssert(pent[cent].sz);
STATIC SZTEMP szAnswer = { " " };
CHAR chRight = (pent[cent].pentNext == pentNil) ? ' ' : 175;
CCH cch = strlen(pent[cent].sz);
/*
* Build the temporary string.
* After copy, pad the string with spaces.
*/
strncpy(&szAnswer[1],pent[cent].sz,cch);
while (cch < cchMenuMax)
szAnswer[1+cch++] = chSpace;
/*
* Finally, fill in the ending character..
*/
szAnswer[cch+1] = chRight;
szAnswer[cch+2] = chNil;
return (szAnswer);
}
/*
* Flash the selected entry
*/
VOID POPUP::Flash(CENT cent,PENT pent,WINDOW &rwnd)
{
for (INT count=0; count < 5; count++)
{
Display(cent,pent,rwnd,fFalse);
delay(40);
Display(cent,pent,rwnd,fTrue);
delay(40);
}
}
/*
* Windows dimensions..
*/
ROW POPUP::RowTopFromCentPent(CENT cent,PENT pent)
{
return (rowTop);
}
COL POPUP::ColLeftFromCentPent(CENT cent,PENT pent)
{
return (colLeft);
}
ROW POPUP::CrowFromCentPent(CENT centMac,PENT pent)
{
return (centMac);
}
COL POPUP::CcolFromCentPent(CENT centMac,PENT pent)
{
cchMenuMax = cchNil;
Assert(pent != pentNil);
for (CENT cent = centNil; cent < centMac; cent++)
{
Assert(pent[cent].sz != szNil);
cchMenuMax = Max(cchMenuMax,strlen(pent[cent].sz));
}
return (cchMenuMax);
}
/*
* Creates and activates a sub-menu for this object.
*/
BOOL POPUP::FSubMenuFromCentPent(CENT cent,PENT pent)
{
PENT pentSub = pent[cent].pentNext;
CENT centSub = pent[cent].centNext;
POPUP pop(rowTop+cent,colRight,centSub,pentSub,szNil);
BOOL fContinue = fTrue;
/*
* If the user "selects" the sub-menu, as opposed to ESCaping, then
* we take that as this menu was selected also.
*/
if (pop.CentGet() != centError)
fContinue = fFalse;
return (fContinue);
}